package com.ruoci.redis.consistency;

import com.ruoci.redis.constants.BusinessConstants;
import com.ruoci.redis.entity.Users;
import com.ruoci.redis.response.BasicResponse;
import com.ruoci.redis.response.ResponseCode;
import com.ruoci.redis.service.UsersService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Author yang
 * 数据一致性(双写模式)
 * A,B两个线程,先修改MySQL的线程却最后执行了Redis的更新。
 * 需要添加分布式锁读写锁
 **/
@Slf4j
@RestController
@RequestMapping("/doubleWrite")
public class DoubleWriteMode {

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private UsersService usersService;

    @GetMapping("/consistence")
    @Transactional(rollbackFor = Exception.class)
    public BasicResponse doubleWrite(){
        RReadWriteLock lock = redissonClient.getReadWriteLock(BusinessConstants.CONSISTENCE_LOCK);
        RLock writeLock = lock.writeLock();
            try {
                //尝试加锁，最多等待100秒，上锁以后10秒自动解锁
                if (writeLock.tryLock(BusinessConstants.TIME_100, BusinessConstants.TIME_10, TimeUnit.SECONDS)) {
                    //更新数据库
                    Users users = new Users();
                    users.setUserCode("172667");
                    users.setUserName("别再晚睡");
                    usersService.updateById(users);
                    List<Users> list = usersService.list();
                    //更新缓存
                    redisTemplate.opsForValue().set(BusinessConstants.USER_DATA,list);
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                writeLock.unlock();
            }
        return new BasicResponse(ResponseCode.SUCCESS.getCode(),BusinessConstants.SUCCESSFULLY_MODIFIED);
    }
}
